/*  NVS: non volatile storage in flash
 *
 * Copyright (c) 2023 Liuis
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2023-09-03     Liuis        The first version.
 */

#include "nvs.h"
#include <stdio.h>
#include <string.h>
#include "stm32wbaxx_hal.h"
#include "flash_manager.h"
#include "log_module.h"
#include "stm32wbaxx_ll_icache.h"

#define NVS_PAGE_SIZE   8192

#define WITH_RADIO_MUTEX 1

#define USR_NVM_SIZE    (NVS_PAGE_SIZE * 3)
#define USR_NVM_STAR_ADDR    (0x081F0000U)
#define FLASH_OFFSET         (0x08000000U)

static uint8_t erase_finish_flag = 0;
static uint8_t write_finish_flag = 0;

static void WriteCallback(FM_FlashOp_Status_t Status)
{
  write_finish_flag = 0;
}

static void PageEraseCallback(FM_FlashOp_Status_t Status)
{
  erase_finish_flag = 0;
	if(Status != FM_OK){
	   LOG_INFO_APP("PageEraseCallback error ......................\r\n");
	}
}

int flash_init (void)
{

    return 0;
}

int flash_read (uint32_t addr, void * data, size_t len)
{
//	LOG_INFO_APP("flash read: addr:%x len:%d \r\n", USR_NVM_STAR_ADDR + addr, len);
//	HAL_Delay(1);
	memcpy(data, (uint8_t*)(USR_NVM_STAR_ADDR + addr), len);
	LL_ICACHE_Invalidate();
  return 0;
}

int flash_write (uint32_t addr, const void * data, size_t len)
{
    static FM_CallbackNode_t callbackNode = {
	  .Callback = WriteCallback,
	};
    write_finish_flag = 1;
	
//	LOG_INFO_APP("flash_write Address:%x  len:%d \r\n", USR_NVM_STAR_ADDR+addr,  len);
//	uint8_t* buf = (uint8_t*)(data);
//	for(int i=0;i<len;i++){
//	  LOG_INFO_APP("%x ", buf[i]);
//	}
//	LOG_INFO_APP("\n");
	FM_Cmd_Status_t fm_status = FM_Write((uint32_t *)(data), (uint32_t*)(USR_NVM_STAR_ADDR+addr), len/4, &callbackNode);
	if(fm_status != FM_OK){
		write_finish_flag = 0;
		LOG_INFO_APP("FM_Write:%x \r\n", fm_status);
		return -1;
	}
    while(write_finish_flag){
	  FM_BackgroundProcess();
	};
		LL_ICACHE_Invalidate();
    return 0;
}

int flash_erase (uint32_t addr, size_t len)
{
	uint32_t Page = (USR_NVM_STAR_ADDR + addr - FLASH_OFFSET)/NVS_PAGE_SIZE;
	uint32_t page_num = len/NVS_PAGE_SIZE;
	static FM_CallbackNode_t callbackNode = {
	  .Callback = PageEraseCallback,
	};
	erase_finish_flag = 1;
	LOG_INFO_APP("flash_erase page:%x  page_num:%x \r\n", Page,  page_num);
  FM_Cmd_Status_t fm_status = FM_Erase(Page, page_num, &callbackNode);
	if(fm_status != FM_OK){
		erase_finish_flag = 0;
		LOG_INFO_APP("FM_Erase:%x \r\n", fm_status);
		return -1;
	}
  while(erase_finish_flag){
	  FM_BackgroundProcess();
	};
	LL_ICACHE_Invalidate();
    return 0;
}

const static struct flash_parameters flash_param =
{
    16, 0xff, NVS_PAGE_SIZE,
    flash_init, 
    flash_read, 
    flash_write, 
    flash_erase
};



/////////////////////////////////////////////////////////////////////////////////


struct nvs_fs fs = 
{
    .offset = 0,
    .sector_size = NVS_PAGE_SIZE,
    .sector_count = 3,
    .flash_params = &flash_param,
};

#define KEY_5   0x0606
uint8_t a5[5] = {0x55, 0x55, 0x55, 0x55, 0x55};

int test_nvs(void)
{
    uint32_t i; 
    int len;
    char str[20];
    uint32_t cnt=0;
    uint8_t buf[5];
    
	
	flash_init();
	
	if (nvs_mount(&fs))
	{
			LOG_INFO_APP("nvs_mount error!\n");
			return -1;
	}
	
	if(nvs_clear(&fs)){
			LOG_INFO_APP("nvs_clear error!\n");
			return -1;
	}
  if (nvs_mount(&fs))
	{
			LOG_INFO_APP("nvs_mount error!\n");
			return -1;
	}
	HAL_Delay(50);
  LOG_INFO_APP("test_nvs write test start:\r\n");
	for(uint32_t i=0;i<10000;i++)
	{
		static uint32_t scount = 0;
		scount++;
		memcpy(a5, &scount, sizeof(uint32_t));
		nvs_write(&fs, KEY_5, a5, sizeof(a5));
		HAL_Delay(1);
		len = nvs_read(&fs, KEY_5, buf, sizeof(a5));
		HAL_Delay(1);
		if (len <= 0)
		{
			LOG_INFO_APP("key not found! %d \n", len);
		}
		else
		{
			  uint32_t count = 0;
			  memcpy(&count, buf, sizeof(uint32_t));
				if(count == scount){
				  //LOG_INFO_APP("OK\n");
					//nvs_delete(&fs, KEY_5);
				}else
				{
					LOG_INFO_APP("Error  %x \n", count);
				}
		}
	}
  LOG_INFO_APP("finish test\r\n"); 
    
    
		return 0;
}








